package com.sp.common.code;

import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.IFill;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.fill.Column;
import org.apache.commons.lang3.StringUtils;
import org.springframework.core.io.DefaultResourceLoader;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


/**
 * 方法描述：查询生成代码
 */
public class MybatisPlusCodeGenerator {

    //数据库连接地址
    public String DB_URL = "";
    public String DB_USER_NAME = "";
    public String DB_PASSWORD = "";

    //包名和模块名
    public String PACKAGE_PARENT = "com.app.common.code";
    //过滤的前缀
    public String[] TABLE_PREFIX = new String[]{};
    //需要生成的表。多个表之间用，隔开
    public String[] INCLUDES = new String[]{};
    //是否使用临时文件夹
    public  Boolean USE_TEMP_OUTPUT = true;
    public  String TEMP_DIR = "";



    public void generateCode() throws Exception {

        //获取包路径
        String path = getExportPath();

        /**
         * 1.数据库配置(设置数据源)
          配置数据库连接以及需要使用的字段
         */
        FastAutoGenerator fastAutoGenerator = FastAutoGenerator.create(DB_URL, DB_USER_NAME, DB_PASSWORD);

        /**
         * 2.全局配置
         * /**
         *          日期类型 DateType
         *          DateType.ONLY_DATE 使用 java.util.date包下的 Date
         *          DateType.SQL_PACK 使用 java.sql包下的 Date
         *          DateType.TIME_PACK   因为会使用 java.time.LocalDateTime jdk1.8以上才支持  (推荐使用)
         *
         */
        fastAutoGenerator.globalConfig(
                globalConfigBuilder -> globalConfigBuilder
                        .fileOverride()     // 覆盖已生成文件
                        .disableOpenDir()   // 不打开生成文件目录
                        .outputDir(path) // 指定输出目录,注意斜杠的表示
                        .author("") // 设置注释的作者
                        .commentDate("yyyy-MM-dd HH:mm:ss") // 设置注释的日期格式
                        .dateType(DateType.TIME_PACK)   // 使用java8新的时间类型
                        .enableSwagger()    // 开启swagger文档

        );

        /**
         * 3.包配置
         */
        fastAutoGenerator.packageConfig(
                packageConfigBuilder -> packageConfigBuilder
                        .parent(PACKAGE_PARENT)   // 设置父包名
                        // .moduleName(MODULE_NAME) // 设置父包模块名
                        .entity("entity") // 设置MVC下各个模块的包名
//                        .other("other")
                        .mapper("mapper")
                        .service("service")
                        .serviceImpl("service.impl")
                        .controller("controller")
                        .xml("mapper.xml") // 设置XML资源文件的目录
//                        .pathInfo(Collections.singletonMap(OutputFile.xml, projectPath + SERVICE_PROJECT_PATH + "\\src\\main" + XML_OUTPUT_PATH))// 设置XML资源文件的目录

        );
        /**
         * 4.策略配置
         */
        fastAutoGenerator.strategyConfig(
                strategyConfigBuilder -> strategyConfigBuilder
                        .enableCapitalMode()    // 开启大写命名
                        .enableSkipView()   // 开启跳过视图
                        .disableSqlFilter() // 禁用sql过滤
                        .addInclude(INCLUDES)  // 设置需要生成的表名
                        .addTablePrefix(TABLE_PREFIX)   // 设置过滤表前缀
        );


        List<IFill> tableFiles = this.getTableFiles();
        /**
         * 4.1 Entity策略配置
         */
        fastAutoGenerator.strategyConfig(
                strategyConfigBuilder -> strategyConfigBuilder.entityBuilder()
                        .enableTableFieldAnnotation()   // 生成实体时生成字段的注解，包括@TableId注解等---
                        .naming(NamingStrategy.underline_to_camel)  // 数据库表和字段映射到实体的命名策略,为下划线转驼峰
                        .columnNaming(NamingStrategy.underline_to_camel)
                        .idType(IdType.AUTO)    // 全局主键类型为AUTO(自增)
                        .enableLombok() // 支持lombok开启注解
                        .logicDeleteColumnName("deleted")   // 逻辑删除字段名(数据库)
                        .logicDeletePropertyName("deleted") // 逻辑删除属性名(实体)
//                        .addTableFills(new Column("create_time", FieldFill.INSERT)) // 自动填充配置  create_time  update_time 两种方式
//                        .addTableFills(new Property("updateTime", FieldFill.INSERT_UPDATE))
                        .addTableFills(tableFiles)
                        .versionColumnName("version")   // 开启乐观锁
                        .disableSerialVersionUID()  // 禁用生成 serialVersionUID，默认值:true
                        .enableChainModel() // 开启实体类链式编程
                        .formatFileName("%sDO") // 实体名称格式化为XXXDO   formatFileName("%sEntity")
        );
        /**
         * 4.2 Controller策略配置
         */
        fastAutoGenerator.strategyConfig(
                strategyConfigBuilder -> strategyConfigBuilder.controllerBuilder()
                        .enableRestStyle()  // 开启生成@RestController控制器
                        .enableHyphenStyle()    // 开启驼峰转连字符 localhost:8080/hello_id_2
        );

        /**
         * 4.3 Service策略配置
         格式化service接口和实现类的文件名称，去掉默认的ServiceName前面的I ----
         */
        fastAutoGenerator.strategyConfig(
                strategyConfigBuilder -> strategyConfigBuilder.serviceBuilder()
                        .formatServiceFileName("%sService")
                        .formatServiceImplFileName("%sServiceImpl"));


        /**
         * 4.4 Mapper策略配置
         格式化 mapper文件名,格式化xml实现类文件名称
         */
        fastAutoGenerator.strategyConfig(
                strategyConfigBuilder -> strategyConfigBuilder.mapperBuilder()
                        .enableMapperAnnotation()   // 开启 @Mapper 注解
                        .formatMapperFileName("%sMapper")
                        .formatXmlFileName("%sMapper"));

        /** 5.生成代码
         *
         */
        // fastAutoGenerator.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板，默认的是Velocity引擎模板

        try {
            fastAutoGenerator.execute();
            System.out.println("-----------------------------代码已经生成---------------------------------------------------------------");
            System.out.println("路径："+path);
            System.out.println("------------------------------------------------------------------------------------------------------");
        }catch (Exception e){
            e.printStackTrace();
            throw new Exception(e.getMessage());
        }
    }



    public static List<IFill> getTableFiles() {

        List<IFill> tableFillList = new ArrayList<>();
        IFill CREATOR_ID = new Column("CREATOR_ID", FieldFill.INSERT);
        IFill CREATED_BY = new Column("CREATED_BY", FieldFill.INSERT);
        IFill CREATE_TIME = new Column("CREATE_TIME", FieldFill.INSERT);
        IFill UPDATER_ID = new Column("UPDATER_ID", FieldFill.INSERT_UPDATE);
        IFill UPDATED_BY = new Column("UPDATED_BY", FieldFill.INSERT_UPDATE);
        IFill UPDATE_TIME = new Column("UPDATE_TIME", FieldFill.INSERT_UPDATE);
        tableFillList.add(CREATOR_ID);
        tableFillList.add(CREATED_BY);
        tableFillList.add(CREATE_TIME);
        tableFillList.add(UPDATER_ID);
        tableFillList.add(UPDATED_BY);
        tableFillList.add(UPDATE_TIME);
        return tableFillList;
    }




    /*
     * 获取需要生成的路径
     * @return
     * @throws IOException
     * @return
     * @throws IOException
     */
    public  String getExportPath() throws IOException{
        // 获取工程路径
        String projectPath = getProjectPath();
        String exportPath;
        if(USE_TEMP_OUTPUT) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
            TEMP_DIR = projectPath + "/temp/" + format.format(new Date());
            exportPath = StringUtils.replaceEach(TEMP_DIR, new String[]{"/", "."},
                    new String[]{File.separator, File.separator});
        } else {
            exportPath = StringUtils.replaceEach(projectPath + "/src/main/java/", new String[]{"/", "."},
                    new String[]{File.separator, File.separator});
        }
        return exportPath;
    }

    /**
     * 获取工程路径
     * @return
     * @throws IOException
     */
    public  String getProjectPath() throws IOException {
        // 获取工程路径
        File projectPath = new DefaultResourceLoader().getResource("").getFile();
        while (!new File(projectPath.getPath() + File.separator + "src").exists()) {
            projectPath = projectPath.getParentFile();
        }
        String path = StringUtils.replaceEach(projectPath.toString(), new String[]{"/", "."},
                new String[]{File.separator, File.separator});
        return path;
    }

}
